<template>
  <Card class="!mt-10px">
    <Form ref="formRef" :model="spu" :rules="rules" :label-col="{ span: 2 }">
      <FormItem label="Spu名称" name="spuName">
        <Input placeholder="请输入Spu名称" v-model:value="spu.spuName" />
      </FormItem>
      <FormItem label="Spu品牌" name="tmId">
        <Select placeholder="请选择Spu品牌" class="!w-200px" v-model:value="spu.tmId">
          <SelectOption v-for="tm in trademarkList" :key="tm.id" :value="tm.id">
            {{ tm.tmName }}
          </SelectOption>
        </Select>
      </FormItem>
      <FormItem label="Spu描述" name="description">
        <Textarea placeholder="请输入Spu描述" v-model:value="spu.description" />
      </FormItem>
      <FormItem label="Spu图片" name="spuImageList">
        <!-- 
          v-model:file-list="fileList" 上传多个图片文件列表
          @preview="handlePreview" 点击预览触发的事件
          before-upload 上传之前回调不能阻止上传，在change中判断再删除多余的图片
         -->
        <Upload
          v-model:file-list="spu.spuImageList"
          :action="`${apiUrl}/admin/product/fileUpload`"
          list-type="picture-card"
          @preview="handlePreview"
          :before-upload="beforeUpload"
          @change="handleChange"
        >
          <div v-if="spu.spuImageList.length < 20">
            <PlusOutlined />
            <div class="ant-upload-text">Upload</div>
          </div>
        </Upload>

        <div>只能上传jpg/png文件，且不超过500kb</div>

        <Modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
          <img alt="预览图片" class="w-full" :src="previewImage" />
        </Modal>
      </FormItem>
      <FormItem label="销售属性" name="spuSaleAttrList">
        <!-- FormItem组件只能包裹一个表单元素 -->
        <FormItem>
          <Select
            placeholder="请选择销售属性"
            class="!w-200px !mr-20px"
            v-model:value="selectedBaseSaleAttr"
          >
            <SelectOption
              v-for="baseSaleAttr in filterBaseSaleAttrList"
              :key="baseSaleAttr.id"
              :value="`${baseSaleAttr.id}:${baseSaleAttr.name}`"
            >
              {{ baseSaleAttr.name }}
            </SelectOption>
          </Select>

          <Button type="primary" :disabled="!selectedBaseSaleAttr" @click="addSaleAttr">
            <template #icon><PlusOutlined /></template>
            添加销售属性
          </Button>
        </FormItem>

        <Table
          class="mt-15px"
          :columns="columns"
          :data-source="spu.spuSaleAttrList"
          bordered
          :pagination="false"
          rowKey="id"
        >
          <template #bodyCell="{ column, index, record, text }">
            <template v-if="column.dataIndex === 'id'">
              {{ index + 1 }}
            </template>

            <template v-if="column.dataIndex === 'spuSaleAttrValueList'">
              <Tag
                closable
                color="blue"
                v-for="(spuSaleAttrValue, i) in text"
                :key="spuSaleAttrValue.id || spuSaleAttrValue.uid"
                @close="text.splice(i, 1)"
              >
                {{ spuSaleAttrValue.saleAttrValueName }}
              </Tag>
              <Input
                placeholder="请输入属性值"
                v-if="record.isShowEdit"
                ref="inputRef"
                class="!w-150px"
                v-model:value="saleAttrValue"
                @blur="addSaleAttrValue(record)"
              />
              <Button v-else @click="showEdit(record)">
                <template #icon><PlusOutlined /></template>
                添加属性值
              </Button>
            </template>

            <template v-if="column.dataIndex === 'operator'">
              <Popconfirm
                :title="`您确认要删除 ${record.saleAttrName} 数据吗？`"
                @confirm="spu.spuSaleAttrList.splice(index, 1)"
              >
                <template #icon><QuestionCircleOutlined style="color: red" /></template>
                <Button danger>
                  <template #icon><DeleteOutlined /></template>
                </Button>
              </Popconfirm>
            </template>
          </template>
        </Table>
      </FormItem>
      <FormItem :wrapper-col="{ offset: 2 }">
        <Button type="primary" class="mr-20px" @click="submit"> 确定 </Button>
        <Button @click="cancel"> 取消 </Button>
      </FormItem>
    </Form>
  </Card>
</template>

<script lang="ts">
  import { defineComponent } from 'vue';
  export default defineComponent({
    name: 'SaveOrUpdateSpu',
  });
</script>

<script lang="ts" setup>
  import { ref, reactive, onMounted, computed, nextTick } from 'vue';
  import {
    Card,
    Form,
    FormItem,
    Input,
    Select,
    SelectOption,
    Textarea,
    Upload,
    Table,
    Button,
    Popconfirm,
    Modal,
    message,
    Tag,
  } from 'ant-design-vue';
  import { PlusOutlined, QuestionCircleOutlined, DeleteOutlined } from '@ant-design/icons-vue';
  import { useGlobSetting } from '/@/hooks/setting';
  import { useCategoryStore } from '/@/store/modules/category';
  import { getAllTrademarkListApi } from '/@/api/product/trademark';
  import {
    getBaseSaleAttrListApi,
    saveSpuApi,
    getSpuImageListApi,
    getSpuSaleAttrListApi,
    updateSpuApi,
  } from '/@/api/product/spu';
  import type { FileInfo, FileItem } from '../../file';
  import type { TrademarkListModel } from '/@/api/product/model/trademarkModel';
  import type {
    BaseSaleAttrListModel,
    SpuSaleAttrListModel,
    SpuSaleAttrModel,
    SpuModel as CurrentSpuModel,
  } from '/@/api/product/model/spuModel';
  import type { SpuModel } from './types';
  import type { RuleObject } from 'ant-design-vue/es/form';

  const emit = defineEmits(['setIsShow']);
  const props = defineProps<{
    currentSpu: CurrentSpuModel;
  }>();

  const categoryStore = useCategoryStore();

  // 表单数据
  const spu = reactive<SpuModel>({
    id: props.currentSpu.id,
    spuName: props.currentSpu.spuName,
    tmId: props.currentSpu.tmId,
    description: props.currentSpu.description,
    spuImageList: [],
    spuSaleAttrList: [],
  });
  // 自定义表单校验函数
  const spuSaleAttrListValidator = (_rule: RuleObject, value: SpuSaleAttrListModel) => {
    /*
      rule 是表单规则
      value 表单项的值
    */
    if (!value.length) {
      return Promise.reject('请至少添加一个销售属性');
    }

    // 每个销售属性至少添加一个销售属性值
    if (!value.every((saleAttr) => saleAttr.spuSaleAttrValueList.length)) {
      return Promise.reject('每个销售属性至少添加一个销售属性值');
    }

    return Promise.resolve();
  };
  // 表单校验规则
  const rules = {
    spuName: [{ required: true, message: '请输入SPU名称', trigger: 'blur' }],
    tmId: [{ required: true, message: '请选择SPU品牌' }],
    description: [{ required: true, message: '请输入SPU描述' }],
    spuImageList: [{ required: true, message: '请至少上传一张SPU图片', type: 'array' }],
    // type: array 只能判断第一层数组有没有值，不能判断数组中的数组有没有值
    // spuSaleAttrList: [{ required: true, message: '请至少添加一个销售属性', type: 'array' }],
    spuSaleAttrList: [{ required: true, validator: spuSaleAttrListValidator }],
  };
  // 提交表单
  const formRef = ref();
  const submit = async () => {
    await formRef.value.validate();
    const { id, spuName, tmId, description, spuImageList, spuSaleAttrList } = spu;
    const { category3Id } = categoryStore;

    const data = {
      id,
      spuName,
      tmId,
      description,
      spuImageList: spuImageList.map((img) => {
        return {
          imgName: img.name,
          imgUrl: img.response.data,
        };
      }),
      spuSaleAttrList,
      category3Id,
    };

    if (id) {
      await updateSpuApi(data);
    } else {
      await saveSpuApi(data);
    }

    message.success(`${id ? '更新' : '添加'}SPU成功`);
    cancel();
  };

  const trademarkList = ref<TrademarkListModel>([]);
  const baseSaleAttrList = ref<BaseSaleAttrListModel>([]);

  // 可以有多个相同的生命周期函数的
  // 发送请求，获取基础销售属性数据
  onMounted(async () => {
    baseSaleAttrList.value = await getBaseSaleAttrListApi();
  });
  // 发送请求，获取品牌数据
  onMounted(async () => {
    trademarkList.value = await getAllTrademarkListApi();
  });
  // 更新Spu使用：看是否有id
  // 获取图片列表
  onMounted(async () => {
    if (!spu.id) return;
    const spuImageList = await getSpuImageListApi(spu.id);
    // 将响应回来的类型 { "id": 672,"spuId": 245,"imgName":"4.png","imgUrl": "xxx"},
    // 改为 FileItem 类型
    spu.spuImageList = spuImageList.map((img) => {
      return {
        uid: img.id + '',
        name: img.imgName,
        status: 'done',
        response: {
          data: img.imgUrl,
        },
        url: img.imgUrl,
      };
    });
  });
  // 获取销售属性列表
  onMounted(async () => {
    if (!spu.id) return;
    spu.spuSaleAttrList = await getSpuSaleAttrListApi(spu.id);
  });

  // 销售属性计算
  const filterBaseSaleAttrList = computed(() => {
    return baseSaleAttrList.value.filter((baseSaleAttr) => {
      // 返回true 保留
      // 返回false 过滤
      // baseSaleAttr在不在spuSaleAttrList里面，在就要过滤
      return !spu.spuSaleAttrList.find(
        (spuSaleAttr) => spuSaleAttr.baseSaleAttrId === baseSaleAttr.id,
      );
    });
  });

  // 收集基础销售属性数据
  const selectedBaseSaleAttr = ref<string | undefined>();

  // 添加销售属性
  const addSaleAttr = () => {
    // 切割的数据类型是字符串
    const [id, name] = (selectedBaseSaleAttr.value as string).split(':');
    // 添加
    spu.spuSaleAttrList.push({
      baseSaleAttrId: +id, // 记得转number类型
      saleAttrName: name,
      isShowEdit: false, // 按钮和Input的切换显示的标识
      spuSaleAttrValueList: [
        // {
        //   baseSaleAttrId: 0,
        //   id: 0,
        //   isChecked: 'string',
        //   saleAttrName: 'string',
        //   saleAttrValueName: 'string',
        //   spuId: 0,
        // },
      ],
    });
    // 清空选中的数据
    selectedBaseSaleAttr.value = undefined;
  };

  const inputRef = ref();
  // 进入编辑模式
  const showEdit = async (record: SpuSaleAttrModel) => {
    record.isShowEdit = true;
    await nextTick();
    inputRef.value.focus();
  };

  const saleAttrValue = ref('');
  const addSaleAttrValue = (record: SpuSaleAttrModel) => {
    if (saleAttrValue.value) {
      record.spuSaleAttrValueList.push({
        baseSaleAttrId: record.baseSaleAttrId,
        uid: Date.now(), // 为了遍历有key
        saleAttrValueName: saleAttrValue.value,
      });

      saleAttrValue.value = '';
    }

    record.isShowEdit = false;
  };

  const cancel = () => {
    emit('setIsShow', 1);
  };

  const columns = [
    {
      title: '序号', // 列头的标题
      dataIndex: 'id', // 渲染data中哪个数据
      width: 80, // 宽度
      align: 'center', // 居中
    },
    {
      title: '属性名',
      dataIndex: 'saleAttrName',
    },
    {
      title: '属性值列表',
      dataIndex: 'spuSaleAttrValueList',
    },
    {
      title: '操作',
      dataIndex: 'operator',
      width: 100,
    },
  ];

  // 销售属性数据
  // const spuSaleAttrList = ref([]);

  // 图片列表
  // const fileList = ref<FileItem[]>([
  // {
  //   uid: '-1', // 图片的id
  //   name: 'image.png', // 图片名称
  //   status: 'uploading', // 上传图片状态
  //   percent: 100,
  //   url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', // 图片地址
  // },
  // {
  //   uid: '-2', // 图片的id
  //   name: 'image.png', // 图片名称
  //   status: 'error', // 上传图片状态
  //   url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  // },
  // ]);

  // 图片上传地址前缀
  const { apiUrl } = useGlobSetting();

  // 预览图片
  const previewVisible = ref(false); // 对话框显示隐藏
  const previewImage = ref(''); // 预览图片的地址

  const handlePreview = async (file: FileItem) => {
    previewImage.value = file.response.data;
    previewVisible.value = true;
  };

  const handleCancel = () => {
    previewVisible.value = false;
  };

  // 上传图片之前
  const beforeUpload = (file: FileItem) => {
    // file.type 文件类型
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      message.error('只能上传jpg和png格式的图片!');
    }
    // file.size 文件大小
    const isLt = (file.size as number) / 1024 < 500;
    if (!isLt) {
      message.error('图片大小不能超过500KB!');
    }
    // 返回值true ok
    // 返回值false，就不能够上传
    return isJpgOrPng && isLt;
  };

  // 图片上传中触发的回调
  const handleChange = (info: FileInfo) => {
    // console.log(info.file.percent, info.file.status, info);
    // 当上传的图片不符合要求时，直接return
    if (info.file.status === 'uploading') {
      const isJpgOrPng = info.file.type === 'image/jpeg' || info.file.type === 'image/png';
      const isLt = (info.file.size as number) / 1024 < 500;
      if (!isJpgOrPng || !isLt) {
        spu.spuImageList.splice(spu.spuImageList.length - 1, 1);
        return;
      }
    }

    spu.spuImageList = info.fileList;

    // 上传失败：提示错误
    if (info.file.status === 'error') {
      message.error('上传图片失败');
    }
  };
</script>
